home *** CD-ROM | disk | FTP | other *** search
/ PD ROM 1 / PD ROM Volume I - Macintosh Software from BMUG (1988).iso / Stacks / Hyper Utilities / XCMD's⁄XFCN's / SortXFCN / SortXFCN.p < prev    next >
Encoding:
Text File  |  1988-01-09  |  10.1 KB  |  297 lines  |  [TEXT/ttxt]

  1. {[n+,u+,r+,d+,#+,j=13-/40/1o,t=2,o=95] PasMat formatting options}
  2. {------------------------------------------------------------------------------
  3.  
  4. FILE SortXFCN.p
  5.  
  6. NAME
  7.   SortXFCN
  8.  
  9. DESCRIPTION
  10.  This HyperCard external function sorts numerically the contents of the field
  11.  passed as the single parameter.  This field should contain numbers (signed
  12.  reals or integers) separated by spaces.  A typical invocation of the function
  13.  would be:
  14.    Put SortRealsII( inputField ) into outputField
  15.  
  16.  To compile and link using Macintosh Programmer's Workshop 2.0 execute
  17.  the accompanying make file.  This code contains compiler directives to write
  18.  code using the 68881 coprocessor and the 68020 processor.  This results in a
  19.  considerable speed increase on a Mac II.  Remove these directives before
  20.  compiling for other machines.
  21.  
  22. ------------------------------------------------------------------------------}
  23. {$R-}                                  { Turn off range checking }
  24. {$MC68881+}                            { Generate 68881 code }
  25. {$S SortRealsII }
  26.  
  27. UNIT SortXFCN;
  28.  
  29.   {------------------------------------------------------------------------------}
  30.   {----------------------------  INTERFACE Section  -----------------------------}
  31.   {------------------------------------------------------------------------------}
  32.  
  33.   INTERFACE
  34.  
  35.     {------------------------------------------------------------------------------}
  36.     {------------------------------------------------------------------------------}
  37.  
  38.     USES Memtypes, Quickdraw, OSIntf, ToolIntf, HyperXCmd;
  39.  
  40.     PROCEDURE EntryPoint(paramPtr: XCmdPtr);
  41.  
  42.     {------------------------------------------------------------------------------}
  43.     {-------------------------  IMPLEMENTATION Section  ---------------------------}
  44.     {------------------------------------------------------------------------------}
  45.  
  46.   IMPLEMENTATION
  47.  
  48.     {------------------------------------------------------------------------------}
  49.     {------------------------------------------------------------------------------}
  50.  
  51.     PROCEDURE SortRealsII(paramPtr: XCmdPtr);
  52.       FORWARD;
  53.  
  54.     {------------------------------------------------------------------------------}
  55.  
  56.     PROCEDURE EntryPoint(paramPtr: XCmdPtr);
  57.  
  58.       BEGIN
  59.         SortRealsII(paramPtr)
  60.       END                              { entrypoint } ;
  61.  
  62.     {------------------------------------------------------------------------------}
  63.  
  64.     PROCEDURE SortRealsII;
  65.  
  66.     {$MC68020+}                        { Generate 68020 code }
  67.  
  68.       TYPE
  69.         ListPtr      = ^ListInfo;            { Use a linked list to sort the numbers }
  70.         ListInfo     = RECORD
  71.                          str: Str31;    { Keep both string and real forms so that we only }
  72.                          num: Real;        { have to do one conversion between forms. }
  73.                          next: ListPtr;
  74.                        END;
  75.  
  76.       VAR
  77.                 err: OSErr;
  78.         realNumList: ListPtr;
  79.  
  80.       {$I XCmdGlue.inc}
  81.  
  82.         {------------------------------------------------------------------------------}
  83.  
  84.       PROCEDURE SkipSpaces(VAR thePtr: Ptr);
  85.  
  86.         VAR
  87.           pos:         Integer;
  88.  
  89.         BEGIN
  90.           WHILE Chr(thePtr^) = ' ' DO
  91.             BEGIN
  92.               thePtr := Ptr(Ord4(thePtr) + 1);
  93.             END;
  94.         END;
  95.  
  96.       {------------------------------------------------------------------------------}
  97.  
  98.       FUNCTION NextToken(VAR thePtr: Ptr): Str31;
  99.       { Entry conditions :    thePtr points to a memory block which is terminated }
  100.       {                                            with a zero byte.  }
  101.       { Exit conditions :        Any leading spaces are stripped and up to 31 of the }
  102.       {                                            following characters are collected in a Pascal string. }
  103.       {                                            The string is terminated with less than 31 charaters }
  104.             {                                            when a space or the zero byte is encountered after }
  105.       {                                            which thePtr points to that terminating char/byte. }
  106.  
  107.         VAR
  108.           pos:         Integer;
  109.           xferStr:     Str31;
  110.  
  111.         BEGIN
  112.           SkipSpaces(thePtr);
  113.           NextToken := '';
  114.           pos := 0;
  115.           WHILE (thePtr^ <> $00) & (thePtr^ <> $20) & (pos < 31) DO
  116.             BEGIN
  117.               pos := pos + 1;
  118.               xferStr[pos] := Chr(thePtr^);            { Put next character into string }
  119.               thePtr := Ptr(Ord4(thePtr) + 1);    { and advance the pointer. }
  120.             END;
  121.           xferStr[0] := Chr(pos);                                { Set the string length. }
  122.           NextToken := xferStr;
  123.         END;
  124.  
  125.       {------------------------------------------------------------------------------}
  126.  
  127.       FUNCTION StringToReal(str: Str31): Real;
  128.       { Entry conditions :    str is a valid string representation of a signed real }
  129.       {                                            containing only digits, '.', and optionally '+' or '-'. }
  130.  
  131.         VAR
  132.           i, decPos, startPos, sign: Integer;
  133.           tempReal, fraction: Real;
  134.  
  135.         BEGIN
  136.           tempReal := 0;
  137.           decPos := pos('.', str);
  138.           IF str[1] IN ['-', '+'] THEN
  139.             startPos := 2
  140.           ELSE
  141.             startPos := 1;
  142.           IF str[1] = '-' THEN
  143.             sign := - 1
  144.           ELSE
  145.             sign := + 1;
  146.           IF decPos = 0 THEN decPos := Length(str) + 1;
  147.           FOR i := startPos TO decPos - 1 DO
  148.             tempReal := 10 * tempReal + Ord(str[i]) - Ord('0');
  149.           fraction := 0;
  150.           FOR i := Length(str) DOWNTO decPos + 1 DO
  151.             fraction := (fraction + Ord(str[i]) - Ord('0')) / 10;
  152.           StringToReal := sign * (tempReal + fraction);
  153.         END;
  154.  
  155.       {------------------------------------------------------------------------------}
  156.  
  157.       PROCEDURE BuildList(VAR firstElement: ListPtr; inputHandle: Handle);
  158.             { Build a list from the Handle to the zero-terminated data structure containing }
  159.             { the list of numbers represented in ASCII form and separated by spaces. }
  160.  
  161.         VAR
  162.             inputFldPtr: Ptr;
  163.           curElement, prevElement: ListPtr;
  164.           numStr:      Str31;
  165.  
  166.         BEGIN
  167.           curElement := ListPtr(NewPtr(SizeOf(ListInfo)));
  168.           prevElement := NIL;
  169.           firstElement := curElement;
  170.           curElement^.next := NIL;
  171.                     HLock(inputHandle);
  172.                     inputFldPtr := inputHandle^;
  173.           numStr := NextToken(inputFldPtr);
  174.           WHILE numStr <> '' DO
  175.             BEGIN
  176.               curElement^.num := StringToReal(numStr);
  177.               curElement^.str := numStr;
  178.               prevElement := curElement;
  179.               curElement := ListPtr(NewPtr(SizeOf(ListInfo)));
  180.               prevElement^.next := curElement;
  181.               numStr := NextToken(inputFldPtr);
  182.             END;
  183.                     HUnlock(inputHandle);
  184.           DisposPtr(Ptr(curElement));
  185.           IF prevElement <> NIL THEN
  186.             prevElement^.next := NIL
  187.           ELSE
  188.             firstElement := NIL;
  189.         END;
  190.  
  191.       {------------------------------------------------------------------------------}
  192.  
  193.       PROCEDURE SwapInfo(ptr1, ptr2: ListPtr);
  194.             { Just as easy to swap info as switch pointers around }
  195.  
  196.         VAR
  197.           num:         Real;
  198.           numStr:      Str31;
  199.  
  200.         BEGIN
  201.           num := ptr1^.num;
  202.           numStr := ptr1^.str;
  203.           ptr1^.num := ptr2^.num;
  204.           ptr1^.str := ptr2^.str;
  205.           ptr2^.num := num;
  206.           ptr2^.str := numStr;
  207.         END;
  208.  
  209.       {------------------------------------------------------------------------------}
  210.  
  211.       PROCEDURE SortList(VAR theList: ListPtr);
  212.             { An awkward sort of selection sort }
  213.  
  214.         VAR
  215.           small:       Real;
  216.           insidePtr, outsidePtr, smallPtr: ListPtr;
  217.  
  218.         BEGIN
  219.           outsidePtr := theList;
  220.           IF theList <> NIL THEN
  221.             WHILE outsidePtr^.next <> NIL DO
  222.               BEGIN
  223.                 insidePtr := outsidePtr^.next;
  224.                 smallPtr := outsidePtr;
  225.                 small := smallPtr^.num;
  226.                 WHILE insidePtr <> NIL DO
  227.                   BEGIN
  228.                     IF insidePtr^.num < small THEN
  229.                       BEGIN
  230.                         smallPtr := insidePtr;
  231.                         small := smallPtr^.num;
  232.                       END;
  233.                     insidePtr := insidePtr^.next;
  234.                   END;
  235.                 SwapInfo(smallPtr, outsidePtr);
  236.                 outsidePtr := outsidePtr^.next;
  237.               END;
  238.  
  239.         END;
  240.  
  241.       {------------------------------------------------------------------------------}
  242.  
  243.       PROCEDURE ListToHandle(numList: ListPtr; VAR theHandle: Handle);
  244.             { Obtain a Handle to a zero-terminated data structure containing the sorted }
  245.             { list represented in ASCII form and separated by spaces. }
  246.  
  247.         VAR
  248.           spacePtr, zeroPtr, tempPtr: Ptr;
  249.           err:         OSErr;
  250.           space, zero: SignedByte;
  251.  
  252.         BEGIN
  253.           space := $20;
  254.           zero := $00;
  255.           theHandle := NewHandle(0);
  256.           WHILE numList <> NIL DO
  257.             BEGIN
  258.               tempPtr := Ptr(Ord4(@numList^.str) + 1);        { Point to first char in string and }
  259.                                                                                                                     { append characters to theHandle^^ }
  260.                              err := PtrAndHand(tempPtr, theHandle, Length(numList^.str));
  261.               numList := numList^.next;
  262.               IF numList <> NIL THEN                                           { If it's not the last number in }
  263.                 err := PtrAndHand(@space, theHandle, 1);    { the list then append a space. }
  264.             END;
  265.           err := PtrAndHand(@zero, theHandle, 1);                    { Terminate with 0 byte }
  266.         END;
  267.  
  268.       {------------------------------------------------------------------------------}
  269.  
  270.       PROCEDURE DisposeList(VAR theList: ListPtr);
  271.  
  272.         VAR
  273.           tempPtr:     ListPtr;
  274.  
  275.         BEGIN
  276.           tempPtr := theList;
  277.           WHILE tempPtr <> NIL DO
  278.             BEGIN
  279.               tempPtr := theList^.next;
  280.               DisposPtr(Ptr(theList));
  281.               theList := tempPtr;
  282.             END;
  283.         END;
  284.  
  285.       {------------------------------------------------------------------------------}
  286.       {-------------------------  PROCEDURE SortRealsII  ----------------------------}
  287.       {------------------------------------------------------------------------------}
  288.  
  289.       BEGIN
  290.         BuildList(realNumList, paramPtr^.Params[1]);
  291.         SortList(realNumList);
  292.         ListToHandle(realNumList, paramPtr^.returnValue);
  293.         DisposeList(realNumList);
  294.       END;
  295.  
  296. END.
  297.